import json
import os
import random
import re
import string
import subprocess
import tempfile

import requests

from utils.common.time_util import get_time_stamp13_now


def generate_random_number(n):
    """生成n位长度的随机数字串"""
    digits = string.digits
    return ''.join(random.choice(digits) for _ in range(n))


def chinese_to_unicode(text):
    """将中文转成unicode"""
    return ''.join(f'\\u{ord(c):04x}' for c in text)


class QualtricsExplain(object):

    def __init__(self, link):
        self.link = link
        self.json_explained_param = ""

    @staticmethod
    def build_questions(qr):
        for key in qr:
            cur_item = qr[key]
            if 'MC' == cur_item['Type']:
                cur_it = cur_item['Selector']
                if 'SAVR' == cur_it or "SB" == cur_it or "SAHR" == cur_it or "SB" == cur_it:  # 单选
                    # 如果Choices项的值是否为空json数组或者空json对象则说明该题目实际为描述题，需要跳过不处理
                    if len(cur_item['Choices']) <= 0:
                        continue
                    cur_answer = cur_item['ChoiceOrder'][0]  # 默认选第一个
                    cur_item['Selected'] = str(cur_answer)  # 选项答案
                    cur_item['Choices'][str(cur_answer)]['Selected'] = True
                elif 'MAVR' == cur_it or 'MACOL' == cur_it:  # 多选
                    # 如果Choices项的值是否为空json数组或者空json对象则说明该题目实际为描述题，需要跳过不处理
                    if len(cur_item['Choices']) <= 0:
                        continue
                    # if len(cur_item['Choices']) < 2:
                    #     continue
                    for j in range(1, 3):  # 默认选第1,2个
                        cur_item['Choices'][cur_item['ChoiceOrder'][j-1]]['Selected'] = True
                elif 'DL' == cur_it:  # 下拉选
                    cur_answer = cur_item['ChoiceOrder'][0]  # 默认选第一个
                    cur_item['Selected'] = str(cur_answer)  # 选项答案
                    cur_item['Choices'][str(cur_answer)]['Selected'] = True
                elif 'NPS' == cur_it:  # nps量表
                    cur_answer = cur_item['ChoiceOrder'][0]  # 默认选第一个
                    cur_item['Selected'] = str(cur_answer)  # 选项答案
                    cur_item['Choices'][str(cur_answer)]['Selected'] = True
            elif 'TE' == cur_item['Type']:
                cur_it = cur_item['Selector']
                if 'SL' == cur_it or 'ML' == cur_it or 'ESTB' == cur_it or 'PW' == cur_it:  # 填空
                    cur_answer = '无'
                    cur_item['Value'] = cur_answer  # 填空内容
                elif 'FORM' == cur_it:  # 多项填空
                    for c_key in cur_item['Choices']:
                        cur_item['Choices'][c_key]['Text'] = '无'
            elif 'Slider' == cur_item['Type']:
                cur_it = cur_item['Selector']
                if 'HSLIDER' == cur_it or 'HBAR' == cur_it:  # 矩阵滑动条，也可能是只有一行的普通滑动条
                    for c_key in cur_item['Choices']:
                        cur_item['Choices'][c_key]['Selected'] = True
                        cur_item['Choices'][c_key]['NASelected'] = False
                        cur_item['Choices'][c_key]['ToolTipActive'] = False
                        cur_item['Choices'][c_key]['Value'] = 1
                elif 'STAR' == cur_it:  # 矩阵量表，也可能是只有一行的普通量表
                    pass
            elif 'RO' == cur_item['Type']:  # 排序选择
                # 如果Choices项的值是否为空json数组或者空json对象则说明该题目实际为描述题，需要跳过不处理
                if len(cur_item['Choices']) <= 0:
                    continue
                for c_key in cur_item['Choices']:
                    cur_item['Choices'][c_key]['Selected'] = True
                    cur_item['Choices'][c_key]['Value'] = int(c_key) + 1
                    if int(c_key) >= len(cur_item['ChoiceOrder']):
                        cur_item['Choices'][c_key]['Value'] = 1  # 最后一个排到第一位
            elif 'Matrix' == cur_item['Type']:  # 矩阵类
                cur_it = cur_item['Selector']
                answer_1 = cur_item['AnswerOrder'][0]
                if 'Likert' == cur_it:  # 文字在左和上，有效区为选择区
                    if 'SingleAnswer' == cur_item['SubSelector']:  # 矩阵单选
                        for c_key in cur_item['Choices']:
                            cur_item['Choices'][c_key]['Selected'] = answer_1
                            answers = cur_item['Choices'][c_key]['Answers']
                            answers[answer_1]['Selected'] = True
                            cur_item['Choices'][c_key]['SelectedDisplay'] = answers[answer_1]['Display']
                    elif 'MultipleAnswer' == cur_item['SubSelector']:  # 矩阵多选
                        row_count = 0
                        answer_2 = cur_item['AnswerOrder'][1]
                        for c_key in cur_item['Choices']:
                            cur_item['Choices'][c_key]['Selected'] = answer_1 + ',' + answer_2
                            answers = cur_item['Choices'][c_key]['Answers']
                            answers[answer_1]['Selected'] = True
                            answers[answer_2]['Selected'] = True
                            row_count += 1
                        cur_item['rowCount'] = row_count
                        cur_item['WhiteSpacePoint'] = 2  # 暂定
                        cur_item['RedrawHeaderPoint'] = row_count - 1  # 暂定
                    elif 'DL' == cur_item['SubSelector']:  # 矩阵下拉
                        for c_key in cur_item['Choices']:
                            cur_item['Choices'][c_key]['Selected'] = answer_1
                            answers = cur_item['Choices'][c_key]['Answers']
                            answers[answer_1]['Selected'] = True
                            cur_item['Choices'][c_key]['SelectedDisplay'] = answers[answer_1]['Display']
                    else:  # if "DND" == cur_item['SubSelector]:  # 矩阵拖放
                        pass
                elif 'Bipolar' == cur_it:  # 矩阵单选，文字在左和右，有效区为单选
                    answer_1 = cur_item['AnswerOrder'][0]
                    for c_key in cur_item['Choices']:
                        cur_item['Choices'][c_key]['Selected'] = answer_1
                        answers = cur_item['Choices'][c_key]['Answers']
                        answers[answer_1]['Selected'] = True
                        cur_item['Choices'][c_key]['SelectedDisplay'] = answers[answer_1]['Display']
                elif 'RO' == cur_it:  # 矩阵填空，Rank order的简写，文字在左和上，有效区为输入框
                    row_count = 0
                    for c_key in cur_item['Choices']:
                        cur_item['Choices'][c_key]['Selected'] = True
                        answers = cur_item['Choices'][c_key]['Answers']
                        row_count += 1
                        for a_key in answers:
                            answers[a_key]['Selected'] = True
                            answers[a_key]['Value'] = '无'
                    cur_item['rowCount'] = row_count
                    cur_item['WhiteSpacePoint'] = 2  # 暂定
                    cur_item['RedrawHeaderPoint'] = row_count - 1  # 暂定
                elif 'CS' == cur_it:  # 矩阵计算总和，常量计算总和，文字在左和上，有效区为输入框(可输入负数)，最右边有自动计算该行总和的Total列
                    raise Exception('矩阵计算总和,暂时不支持')
                elif 'TE' == cur_it:  # 矩阵填空，Text entry的简写，文字在左和上，有效区为输入框
                    pass
                elif 'MaxDiff' == cur_it:  # 矩阵单选，文字在中间和上边，有效区为两列单选且分布于文字两边
                    for c_key in cur_item['Choices']:
                        cur_item['Choices'][c_key]['Selected'] = answer_1
                        answers = cur_item['Choices'][c_key]['Answers']
                        answers[answer_1]['Selected'] = True
                        cur_item['Choices'][c_key]['SelectedDisplay'] = answers[answer_1]['Display']
                else:  # 未知
                    pass
                pass
            elif 'SBS' == cur_item['Type']:  # "并排矩阵"：文字在左和上的多组双列矩阵
                for cd_key in cur_item['Children']:
                    cd_it = cur_item['Children'][cd_key]
                    if 'Likert' == cd_it['Selector']:  # todo 其他类型
                        if 'SingleAnswer' == cd_it['SubSelector']:  # 矩阵单选
                            row_count = 0
                            for c_key in cd_it['Choices']:
                                cd_it['Choices'][c_key]['Selected'] = '1'
                                answers = cd_it['Choices'][c_key]['Answers']
                                answers['1']['Selected'] = True
                                row_count += 1
                            cur_item['rowCount'] = row_count
                            cur_item['WhiteSpacePoint'] = 2  # 暂定
                            cur_item['RedrawHeaderPoint'] = row_count - 1  # 暂定
            elif 'DB' == cur_item['Type']:  # "占位题";//显示文本，图像，或文件
                pass
            elif 'Timing' == cur_item['Type']:  # "占位题";//页面计时器
                pass
            elif 'Meta' == cur_item['Type']:  # "占位题";//元数据，比如Selector值为Browser表明为浏览器相关信息
                pass
            cur_item['IsResponseSummary'] = False
            cur_item['SeparatorDisplayed'] = True
        result = qr
        return result

    @staticmethod
    def build_answer_of_servey(self, src_data_json):
        qr = src_data_json['QuestionRuntimes']
        qr = self.build_questions(qr)
        sm = src_data_json['SM']
        sm['FlashVersion'] = -1
        sm['JavaSupport'] = 0
        sm['Resolution'] = "1920x1080"
        result = {
            "ED": src_data_json['ED'],
            "EDMETA": {},
            "FormRuntime": src_data_json['FormRuntime'],
            "FormSessionID": src_data_json['FormSessionID'],
            "PageAnalytics": {},
            "ProgressState": [],
            "Questions": qr,
            "RuntimePayload": src_data_json['RuntimePayload'],
            "SM": sm,
            "TransactionID": src_data_json['TransactionID']
        }
        return json.dumps(result)

    def pre_submit(self, src_data):
        """预提交，提交用于获取下一页内容，答案填写"""
        data_1_json = json.loads(src_data)
        jfe_val = data_1_json['SM']['JFEDataCenter']
        cur_header = dict()
        cur_header['content-type'] = 'application/json; charset=utf-8'
        cur_header['user-agent'] = (
            'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) '
            'Chrome/98.0.4758.102 Safari/537.36 NetType/WIFI MicroMessenger/6.8.0(0x16080000) '
            'MacWechat/3.8.3(0x13080310) XWEB/30817 Flue')  # 模拟微信请求头
        link_sep_arr = self.link.split('jfe')
        # 如果链接包含问号？，则去掉问号及以后的部分（少数链接会有这种情况）
        if '?' in self.link:
            pure_link = self.link.split('?')[0]
            link_sep_arr = pure_link.split('jfe')
        url = link_sep_arr[0] + jfe_val + link_sep_arr[1] + '/next'
        rand = generate_random_number(9)
        tid = data_1_json['TransactionID']  # 1
        timestamp = get_time_stamp13_now()
        send_param = f'rand={rand}&tid={tid}&t={timestamp}'
        print('url=', url)
        print('send_param==>', send_param)
        post_body = self.build_answer_of_servey(self, data_1_json)
        print('post_body=', post_body)

        response = requests.post(url, params=send_param, json=json.loads(post_body), headers=cur_header)
        print('response.text=', response.text)

        # 验证结果
        resp_json = json.loads(response.text)
        prog_percent = resp_json['ProgressPercent']
        print(resp_json['Messages'])
        resp_list = list()
        resp_list.append(data_1_json)
        resp_list.append(resp_json)
        if 100 == prog_percent:
            # 如果request_str内容包含汉字则这里呈现方式有可能为unicode，需要将汉字转化为unicode
            request_str = resp_json['Messages']['EOSMessage']['FinalEOSMessage']
            if ('Your response has been recorded' in request_str
                    or '已记录您的回复。' in request_str or chinese_to_unicode('已记录您的回复。') in request_str
                    or '感谢您的参与' in request_str or chinese_to_unicode('感谢您的参与') in request_str):
                print('submit ok')
            else:
                print('next page or failed')
        else:
            self.recursion_next_page(cur_header, resp_json, url, resp_list)
        if 2 < len(resp_list):  # 包含分页
            # 将多页的response组合成一个
            first_resp = resp_list.pop()
            qst_id_lst = list()
            qst_def_dct = dict()
            qst_rt_dct = dict()
            qst_id_lst.extend(first_resp['QuestionIDs'])
            qst_def_dct.update(first_resp['QuestionDefinitions'])
            qst_rt_dct.update(first_resp['QuestionRuntimes'])
            for cur_resp in resp_list:
                qst_id_lst.extend(cur_resp['QuestionIDs'])
                qst_def_dct.update(cur_resp['QuestionDefinitions'])
                qst_rt_dct.update(cur_resp['QuestionRuntimes'])
            first_resp['QuestionIDs'] = qst_id_lst
            first_resp['QuestionDefinitions'] = qst_def_dct
            first_resp['QuestionRuntimes'] = qst_rt_dct
            return json.dumps(first_resp)
        return src_data
        pass  # todo 跳题抛出异常,能否检查出跳题？

    def recursion_next_page(self, cur_header, resp_json, url, resp_list):
        rand = generate_random_number(9)
        tid = resp_json['TransactionID']  # 3,5,7
        page_num = (int(tid) + 1) / 2
        print(f'----------------------------开启新一轮查提交(当前为第{page_num}页)-------------------------------')
        timestamp = get_time_stamp13_now()
        send_param = f'rand={rand}&tid={tid}&t={timestamp}'
        print('url=', url)
        print('send_param=', send_param)
        post_body = self.build_answer_of_servey(self, resp_json)
        print('post_body=', post_body)
        response2 = requests.post(url, params=send_param, json=json.loads(post_body), headers=cur_header)
        print('response2.text=', response2.text)
        resp_json = json.loads(response2.text)
        resp_list.append(resp_json)
        prog_percent2 = resp_json['ProgressPercent']
        if 100 == prog_percent2:
            # 如果request_str内容包含汉字则这里呈现方式有可能为unicode，需要将汉字转化为unicode
            request_str = resp_json['Messages']['EOSMessage']['FinalEOSMessage']
            if ('Your response has been recorded' in request_str
                    or '已记录您的回复。' in request_str or chinese_to_unicode('已记录您的回复。') in request_str
                    or '感谢您的参与' in request_str or chinese_to_unicode('感谢您的参与') in request_str):
                print('submit ok')
            else:
                print('next page or failed')
        else:
            print('递归吧，孩子！')
            self.recursion_next_page(cur_header, resp_json, url, resp_list)

    def get_initial_state_obj(self):
        # 假设response是包含HTML响应的字符串
        header = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
        }
        # link = 'https://qfreeaccountssjc1.az1.qualtrics.com/jfe/form/SV_3gQT7RjkJi5eqFw'
        response = requests.get(self.link, allow_redirects=False, headers=header, timeout=10)
        content = response.text
        # content = response.content.decode('utf-8')
        pattern = r'.*?\((\{"FormSessionID".*?\})\)'
        find_result = re.findall(pattern, content)
        if len(find_result) < 1:
            print("未找到数据")
        print(find_result)
        data_1 = find_result[0]
        print(data_1)
        new_data = self.pre_submit(data_1)
        self.json_explained_param = new_data

    def convert_to_common_struct(self):
        src_data = self.json_explained_param
        if not src_data:
            return ""
        # 保存 src_data 到临时文件
        with tempfile.NamedTemporaryFile(delete=False) as temp_file:
            temp_file.write(src_data.encode())
        # 执行 Node.js 脚本，并从临时文件中读取数据
        current_dir = os.getcwd()
        js_file = current_dir + '/js_file/qualtrics/retrieve2invoke.js'
        p = subprocess.Popen(['node', js_file, temp_file.name], stdout=subprocess.PIPE)
        res = p.stdout.read().decode().strip()
        # 删除临时文件
        temp_file.close()
        os.remove(temp_file.name)
        if not res:
            return ""
        return json.loads(res)

    def do_explain(self):
        self.get_initial_state_obj()
        return self.convert_to_common_struct()
